﻿// Decompiled with JetBrains decompiler
// Type: System.Web.Razor.Parser.SyntaxTree.Block
// Assembly: System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: 682513D6-F37E-48AC-9909-F3EE103CFF14
// Assembly location: D:\Project\Idea\无人机外网\uav\客户端工程\排查工具\bin\Release\System.Web.Razor.dll

using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Razor.Generator;
using System.Web.Razor.Resources;
using System.Web.Razor.Text;

namespace System.Web.Razor.Parser.SyntaxTree
{
  /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Represents the block for creating webpages.</summary>
  public class Block : SyntaxTreeNode
  {
    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Initializes a new instance of the <see cref="T:System.Web.Razor.Parser.SyntaxTree.Block" /> class.</summary>
    /// <param name="source">The source for the block builder.</param>
    public Block(BlockBuilder source)
    {
      if (!source.Type.HasValue)
        throw new InvalidOperationException(RazorResources.Block_Type_Not_Specified);
      this.Type = source.Type.Value;
      this.Children = (IEnumerable<SyntaxTreeNode>) source.Children;
      this.Name = source.Name;
      this.CodeGenerator = source.CodeGenerator;
      source.Reset();
      foreach (SyntaxTreeNode child in this.Children)
        child.Parent = this;
    }

    internal Block(
      BlockType type,
      IEnumerable<SyntaxTreeNode> contents,
      IBlockCodeGenerator generator)
    {
      this.Type = type;
      this.CodeGenerator = generator;
      this.Children = contents;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the type of code block.</summary>
    /// <returns>The type of code block.</returns>
    public BlockType Type { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets a collection of SyntaxTreeNode to view the children of the block.</summary>
    /// <returns>A collection of SyntaxTreeNode to view the children of the block.</returns>
    public IEnumerable<SyntaxTreeNode> Children { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the string name of the block.</summary>
    /// <returns>The string name of the block.</returns>
    public string Name { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the IBlockCodeGenerator to generate codes for the elements.</summary>
    /// <returns>The IBlockCodeGenerator to generate codes for the elements.</returns>
    public IBlockCodeGenerator CodeGenerator { get; private set; }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets a value that indicates whether the object is a block-level object.</summary>
    /// <returns>true if the object is a block-level object; otherwise, false.</returns>
    public override bool IsBlock => true;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the start to identify the specific location of the block.</summary>
    /// <returns>The start to identify the specific location of the block.</returns>
    public override SourceLocation Start
    {
      get
      {
        SyntaxTreeNode syntaxTreeNode = this.Children.FirstOrDefault<SyntaxTreeNode>();
        return syntaxTreeNode == null ? SourceLocation.Zero : syntaxTreeNode.Start;
      }
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Gets the length value of the block.</summary>
    /// <returns>The length value of the block.</returns>
    public override int Length => this.Children.Sum<SyntaxTreeNode>((Func<SyntaxTreeNode, int>) (child => child.Length));

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Finds the first descendent span of the block.</summary>
    /// <returns>The first descendent span of the block.</returns>
    public Span FindFirstDescendentSpan()
    {
      SyntaxTreeNode syntaxTreeNode = (SyntaxTreeNode) this;
      while (syntaxTreeNode != null && syntaxTreeNode.IsBlock)
        syntaxTreeNode = ((Block) syntaxTreeNode).Children.FirstOrDefault<SyntaxTreeNode>();
      return syntaxTreeNode as Span;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Finds the last descendent span of the block.</summary>
    /// <returns>The last descendent span of the block.</returns>
    public Span FindLastDescendentSpan()
    {
      SyntaxTreeNode syntaxTreeNode = (SyntaxTreeNode) this;
      while (syntaxTreeNode != null && syntaxTreeNode.IsBlock)
        syntaxTreeNode = ((Block) syntaxTreeNode).Children.LastOrDefault<SyntaxTreeNode>();
      return syntaxTreeNode as Span;
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Accepts the parser visitor of the block.</summary>
    /// <param name="visitor">The parser visitor.</param>
    public override void Accept(ParserVisitor visitor) => visitor.VisitBlock(this);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns a string that represents the current object.</summary>
    /// <returns>A string that represents the current object.</returns>
    public override string ToString() => string.Format((IFormatProvider) CultureInfo.CurrentCulture, "{0} Block at {1}::{2} (Gen:{3})", (object) this.Type, (object) this.Start, (object) this.Length, (object) this.CodeGenerator);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Determines whether the specified object is equal to the current block.</summary>
    /// <returns>true if the specified object is equal to the current block; otherwise, false.</returns>
    /// <param name="obj">The object to compare with the current object.</param>
    public override bool Equals(object obj) => obj is Block block && this.Type == block.Type && object.Equals((object) this.CodeGenerator, (object) block.CodeGenerator) && Block.ChildrenEqual(this.Children, block.Children);

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns the hash code for this instance.</summary>
    /// <returns>The hash code for this instance.</returns>
    public override int GetHashCode() => (int) this.Type;

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Flattens a collection of a specified type for the block.</summary>
    /// <returns>A collection of a specified type for the block to flatten.</returns>
    public IEnumerable<Span> Flatten()
    {
      foreach (SyntaxTreeNode child in this.Children)
      {
        if (child is Span span2)
        {
          yield return span2;
        }
        else
        {
          foreach (Span span in (child as Block).Flatten())
            yield return span;
        }
      }
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Locates the owner of the block.</summary>
    /// <returns>The owner of the block to locate.</returns>
    /// <param name="change">The text change.</param>
    public Span LocateOwner(TextChange change)
    {
      Span span = (Span) null;
      foreach (SyntaxTreeNode child in this.Children)
      {
        if (!(child is Span target2))
          span = ((Block) child).LocateOwner(change);
        else if (change.OldPosition >= target2.Start.AbsoluteIndex)
          span = target2.EditHandler.OwnsChange(target2, change) ? target2 : span;
        else
          break;
        if (span != null)
          break;
      }
      return span;
    }

    private static bool ChildrenEqual(
      IEnumerable<SyntaxTreeNode> left,
      IEnumerable<SyntaxTreeNode> right)
    {
      IEnumerator<SyntaxTreeNode> enumerator1 = left.GetEnumerator();
      IEnumerator<SyntaxTreeNode> enumerator2 = right.GetEnumerator();
      while (enumerator1.MoveNext())
      {
        if (!enumerator2.MoveNext() || !object.Equals((object) enumerator1.Current, (object) enumerator2.Current))
          return false;
      }
      return !enumerator2.MoveNext();
    }

    /// <summary>This type/member supports the .NET Framework infrastructure and is not intended to be used directly from your code.Returns a value indicating whether the block is equivalent to the same element.</summary>
    /// <returns>true if the block is equivalent to the same element; otherwise, false.</returns>
    /// <param name="node">The syntax tree node.</param>
    public override bool EquivalentTo(SyntaxTreeNode node) => node is Block block && block.Type == this.Type && this.Children.SequenceEqual<SyntaxTreeNode>(block.Children, (IEqualityComparer<SyntaxTreeNode>) new EquivalenceComparer());
  }
}
